package com.darwin.darwinDll.core
{
	import com.darwin.darwinDebug.Debug;
	import com.darwin.darwinDll.analyze.AnalyzeDictionary;
	import com.darwin.darwinDll.analyze.IAnalyze;
	import com.darwin.darwinDll.event.DllEvent;
	import com.darwin.darwinUtils.CRC32;
	import com.darwin.darwinUtils.Priority;
	import com.darwin.darwinUtils.SharedObjectUtil;
	
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoaderDataFormat;
	import flash.utils.ByteArray;
	import flash.utils.Dictionary;
	import flash.utils.getTimer;

	/**
	 * 多文件加载器 
	 * @author vanCopper
	 * 
	 */	
	public class DllLoader extends EventDispatcher
	{

		private var _URLLoader:Class;
		
		/**
		 * 加载项列表 
		 */		
		private var _loaderList:Vector.<DllItem> = new Vector.<DllItem>();
		
		/**
		 * 当前加载索引 
		 */		
		private var _currentIndex:int = 0;
		
		/**
		 * 加载进程是否暂停 
		 */		
		private var _isPause:Boolean = false;
		private var _isRuning:Boolean = false;
		
		/**
		 * 解析器完成计数 
		 */		
		private var _analyzeIndex:int = 0;
		
		private var _totalSize:int = 0;
		
		/**
		 * 加载组字典 保存加载项
		 */		
		private var _groupDic:Dictionary = new Dictionary();
		
		/**
		 * 加载组字典 保存对应组已加载索引 
		 */		
		private var _groupProgressDic:Dictionary = new Dictionary();
		
		/**
		 * 如果加载组的加载进度是基于真实文件大小，该字典保存的数据为 各单个加载组的文件总大小 
		 */		
		private var _groupRealTotalSizeDic:Dictionary = new Dictionary();
		
		/**
		 *  如果加载组的加载进度是基于真实文件大小，该字典保存的数据为 单个组已加载文件的大小
		 */		
		private var _groupRealProgressDic:Dictionary = new Dictionary();
		
		/**
		 * 加载最大线程数 
		 */		
		private var _thread:int;
		
		/**
		 *  
		 * @param loader 可以是远程loader 也可以是本地loader
		 * 
		 */		
		public function DllLoader(loader:Class,thread:int = 1)
		{
			_URLLoader = loader;
			_thread = thread;
			initUrlLoader();
		}
		
		protected var _loaderDic:Vector.<IURLLoader> = new Vector.<IURLLoader>();
		private function initUrlLoader():void
		{
			for (var i:int = 0; i < _thread; i++) 
			{
				var urlLoader:IURLLoader = new _URLLoader();
				urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
				urlLoader.addEventListener(ProgressEvent.PROGRESS,onProgress);
				urlLoader.addEventListener(Event.COMPLETE,onComplete);
				urlLoader.addEventListener(IOErrorEvent.IO_ERROR,onIoError);
				urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onSecurityError);
				_loaderDic.push(urlLoader);
			}
			
		}
		
		private function onIoError(event:IOErrorEvent):void
		{
			var ioErrorEvent:DllEvent = new DllEvent(DllEvent.IO_ERROR);
			dispatchEvent(ioErrorEvent);
			next();
			trace("ioErrorEvent::::::",event);
			//TODO 加载出错后 继续执行下一个加载
		}
		
		private function onSecurityError():void
		{
			// TODO Auto Generated method stub
		}
		
		private function onProgress(e:ProgressEvent):void
		{
			// TODO Auto Generated method stub
		}
		
		private function onError(e:ErrorEvent):void
		{
			trace("onError::::::");
		}
		
		private function onComplete(e:Event):void
		{
			var urlLoader:IURLLoader = e.target as IURLLoader;
			var loaderIndex:int = _loaderDic.indexOf(urlLoader);
			if(loaderIndex != 0)
			{
				var tempLoader:IURLLoader = _loaderDic[0];
				_loaderDic[0] = urlLoader;
				_loaderDic[loaderIndex] = tempLoader;
			}
			Debug.totalLoadedBytes+=urlLoader.bytesTotal;
			currentItemComplete(_currentIndex,urlLoader.data,urlLoader.bytesTotal);
		}
		
		/**
		 * 开始加载  如果重复调用 将直接把列表拼接后继续加载
		 * @param itemList
		 * 
		 */		
		public function load(itemList:Vector.<DllItem>):void
		{
			if(itemList && itemList.length)
			{
				_loaderList = _loaderList.concat(itemList);
				sortItemList();
				if(!isRuning)
				{
					isRuning = true;
					loadItem();
				}
			}
		}
		
		private var _reload:int;//重载次数
		/**
		 * 单项加载完成 
		 * @param index
		 * @param data
		 * 
		 */		
		protected function currentItemComplete(index:int,data:Object,fileSize:uint):void
		{
			var item:DllItem = _loaderList[index];
			item.endTime = getTimer();
//			item.size = fileSize;
			_totalSize += fileSize;
			
			var fileUrl:String = item.url;
			var fileArr:Array = fileUrl.split("/");
			var shareObjKey:String = item.url;
			
			var fileKey:Array = String(fileArr[fileArr.length-1]).split("__");
			var key:String = String(fileKey[fileKey.length - 1]).split(".")[0];
			var crcKey:String;
			if(fileKey.length == 1)
			{
				crcKey = key;
			}else
			{
				var crc32:CRC32 = new CRC32();
				crc32.update(data as ByteArray);
				var temp:uint = crc32.getValue();
				crcKey= temp.toString(16);
			}
			if(key != crcKey)
			{
				if(_reload < 2)
				{
					var random:String = (new Date().time).toString();
					SharedObjectUtil.fmWriteSharedObject(shareObjKey,random);
					loadItem();
					_reload ++;
					return;
				}
			}
			_reload = 0;

			next();
			var analyze:IAnalyze = AnalyzeDictionary.getInstance().getAnalyze(item.type);
			analyze.analyze(data as ByteArray,item,analyzeComplete);
		}
		
		/**
		 * 加载项解析完成 
		 * 全部加载完成后 派发加载完成事件
		 */		
		protected function analyzeComplete(item:DllItem = null):void
		{
			_analyzeIndex ++;
			
			//总文件列表加载进度
			var progress:String = (_analyzeIndex/total).toFixed(2);
			var progressEvent:DllEvent = new DllEvent(DllEvent.PROGRESS);
			progressEvent.progress = progress
			progressEvent.data = item;
//			progressEvent.groupName = item.groupName;
			dispatchEvent(progressEvent);
			
			//组文件列表加载进度
			groupProgress(item);
			
			if(_analyzeIndex >= total)
			{
				var dllEvent:DllEvent = new DllEvent(DllEvent.COMPLETE);
				dllEvent.progress = "1";
				dllEvent.data = _loaderList.concat();
//				dllEvent.groupName = item.groupName;
				_loaderList.length = 0;
				_currentIndex = 0;
				_analyzeIndex = 0;
				dispatchEvent(dllEvent);
			}
			
			//解析完成 将加载完成后的数据给到外部 DllItem回调 
			var completeFuncList:Vector.<Function> = item.completeFuncList;
			for each(var func:Function in completeFuncList)
			{
				func(item.result);
			}
		}
		
		protected function groupProgress(item:DllItem):void
		{
			var groupName:String = item.groupName;
			if(groupName != "" && _groupDic[groupName])
			{
				_groupProgressDic[groupName] += 1;
				var groupIndex:int = _groupProgressDic[groupName];
				var groupList:Vector.<DllItem> = _groupDic[groupName];
				var groupCompleteEvent:DllEvent;// = new DllEvent(DllEvent.GROUP_COMPLETE);
				var progressEvent:DllEvent;// = new DllEvent(DllEvent.GROUP_PROGRESS);
				var progress:String;
				if(_groupRealTotalSizeDic[groupName])
				{
					var groupTotalSize:int = _groupRealTotalSizeDic[groupName];
					var groupProgressSize:int = _groupRealProgressDic[groupName];
					groupProgressSize += item.size;
					_groupRealProgressDic[groupName] = groupProgressSize;
					if(groupProgressSize >= groupTotalSize)
					{
						groupCompleteEvent = new DllEvent(DllEvent.GROUP_COMPLETE);
						groupCompleteEvent.data = _groupDic[groupName];
						groupCompleteEvent.progress = "1";
						groupCompleteEvent.groupName = groupName;
						dispatchEvent(groupCompleteEvent);
						delete _groupDic[groupName];
						delete _groupProgressDic[groupName];
						delete _groupRealTotalSizeDic[groupName];
						delete _groupRealProgressDic[groupName];
					}
					
					if(groupProgressSize < groupTotalSize)
					{
						progress = (groupProgressSize/groupTotalSize).toFixed(2);
						progressEvent = new DllEvent(DllEvent.GROUP_PROGRESS);
						progressEvent.data = groupList[groupIndex-1];
						progressEvent.progress = progress;
						progressEvent.groupName = groupName;
						dispatchEvent(progressEvent);
					}
					
				}else
				{
					var groupTotal:int = groupList.length;
					
					if(groupIndex >= groupList.length)
					{
						groupCompleteEvent = new DllEvent(DllEvent.GROUP_COMPLETE);
						groupCompleteEvent.data = _groupDic[groupName];
						groupCompleteEvent.progress = "1";
						groupCompleteEvent.groupName = groupName;
						dispatchEvent(groupCompleteEvent);
						delete _groupDic[groupName];
						delete _groupProgressDic[groupName];
					}
					
					if(groupIndex < groupList.length)
					{
						progress = (groupIndex/groupList.length).toFixed(2);
						progressEvent = new DllEvent(DllEvent.GROUP_PROGRESS);
						progressEvent.data = groupList[groupIndex-1];
						progressEvent.progress = progress;
						progressEvent.groupName = groupName;
						dispatchEvent(progressEvent);
					}
				}
			}
		}
		
		/**
		 * 所有项加载完成 
		 * 
		 */		
		protected function allItemComplete():void
		{
			_isRuning = false;
			_isPause = false;
		}
		
		/**
		 * 开始加载 
		 * 
		 */		
		protected function loadItem():void
		{
			if(!_isPause)
			{
				var item:DllItem = _loaderList[_currentIndex];
				var random:String = SharedObjectUtil.fmReadSharedObject(item.url);
				if(random !="")
				{
					item.url = item.url + "?"+random;
				}
				item.status = DllItem.STATUS_LOADING;
				var urlLoader:IURLLoader = _loaderDic[0];
				urlLoader.load(item.url);
				item.startTime = getTimer();
			}
		}
		
		protected function next():void
		{
			if(!_isPause)
			{
				_currentIndex += 1;
				if(_currentIndex >= _loaderList.length)
				{
					allItemComplete();
				}else
				{
					loadItem();
				}
			}
		}
		
		protected function sortItemList():void
		{
			var t:int = getTimer();
			var loadingList:Vector.<DllItem> = _loaderList.slice(0,_currentIndex+1);
			var sortList:Vector.<DllItem> = _loaderList.slice(_currentIndex+1,total);
			sortList.sort(sort);
			function sort(a:DllItem,b:DllItem):int
			{
				if(a.priority > b.priority)
				{
					return -1//a>b
				}else if(a.priority == b.priority)
				{
					return 0;//a=b
				}else
				{
					return 1;//a<b
				}
				return 1;
			}
			_loaderList = loadingList.concat(sortList);
			trace("LoadersortTime::::",getTimer() - t);
		}
		
		/**
		 * 插入需要加载列表 
		 * @param itemList
		 * 
		 */		
		public function insert(itemList:Vector.<DllItem>):void
		{
			if(itemList && itemList.length)
			{
//				_loaderList = _loaderList.concat(itemList);
//				sortItemList();
				load(itemList);
			}
		}
		
		/**
		 * 取消一个列表项的加载 
		 * @param loaderItem
		 * 
		 */		
		public function cancelLoaderItem(loaderItem:DllItem):void
		{
			if(loaderItem != null)
			{
				if(loaderItem.status == DllItem.STATUS_LOADING || loaderItem.status == DllItem.STATUS_LOADED)
				{
					loaderItem.removeAllCompleteFunc();
				}
				
				var index:int = _loaderList.indexOf(loaderItem);
				if(index != -1)
				{
					_loaderList.splice(index,1);
				}
			}
		}
		
		/**
		 * 改变一个已有加载项的优先级 
		 * @param loaderItem 直接改变DllItem.priority后调用该方法刷新列表优先级
		 * 
		 */		
		public function changeItemPriority(loaderItem:DllItem):void
		{
			var index:int = _loaderList.indexOf(loaderItem);
			if(index == -1){return;};
			if(loaderItem.status == DllItem.STATUS_LOADING || loaderItem.status == DllItem.STATUS_LOADED){return;};
			
			if(loaderItem.priority >= Priority.HIGH)
			{
				_loaderList.splice(index,1);
				_loaderList.unshift(loaderItem);
			}else if(loaderItem.priority <= Priority.LOW)
			{
				_loaderList.splice(index,1);
				_loaderList.push(loaderItem);
			}else 
			{
				var mid:int = _loaderList.length/2;
				if(mid != index)
				{
					var tempItem:DllItem = _loaderList[mid];
					_loaderList[mid] = loaderItem;
					_loaderList[index] = tempItem;
				}
				
			}
		}                                              
		
		/**
		 * 是否暂停加载 
		 * 
		 */		
		public function set pause(value:Boolean):void
		{
			_isPause = value;
		}
		
		
		
		/**
		 * 加载一组文件 默认组加载优先与所有加载项 
		 * @param itemList
		 * @param groupName
		 * @priority 加载优先级
		 */		
		public function loadGroup(itemList:Vector.<DllItem>,groupName:String,priority:int = Priority.HIGH,isRealProgress:Boolean = false):void
		{
			var totalSize:int = 0;
			for(var i:int = 0; i<itemList.length; i++)
			{
				var item:DllItem = itemList[i];
				item.priority = priority;
				item.groupName = groupName;
				if(isRealProgress)
				{
					totalSize += item.size;
				}
			}
			
			if(_groupDic[groupName])
			{
				var groupList:Vector.<DllItem> = _groupDic[groupName];
				groupList = groupList.concat(itemList);
				_groupDic[groupName] = groupList;
			}else
			{
				_groupDic[groupName] = itemList;
				_groupProgressDic[groupName] = 0;
			}
			
			if(isRealProgress)
			{
				if(_groupRealTotalSizeDic[groupName] == null)
				{
					_groupRealTotalSizeDic[groupName] = 0;
					_groupRealProgressDic[groupName] = 0;
				}
				_groupRealTotalSizeDic[groupName] += totalSize;
			}
			
			load(itemList);
		}
		

		/**
		 * 总索引数 
		 */
		protected function get total():int
		{
			return _loaderList.length;
		}

		/**
		 * 加载器是否在运行 
		 */
		public function get isRuning():Boolean
		{
			return _isRuning;
		}

		/**
		 * @private
		 */
		public function set isRuning(value:Boolean):void
		{
			_isRuning = value;
		}

		/**
		 * 加载文件的总大小 
		 */
		public function get totalSize():int
		{
			return _totalSize;
		}


	}
}